<?php

if (!class_exists('Redis', false)) throw new Exception("Not install `Redis` plugin");

class RedisRepo
{

	private static $instances = array();

	/**
	 * 得到 RedisDatasource 对象
	 * 
	 * @param  array  $dsn 
	 * @return RedisDatasource
	 */
	static function dsn(array $dsn)
	{

		foreach (array('dbpath') as $key)
        {
        	if ( empty($dsn[$key]) )
        	{
        		throw new RedisError("redis config invalid: {$key}");
        	}
        }

        if ( !isset($dsn['persistent']) ) $dsn['persistent'] = false;
        if ( !isset($dsn['dbindex']) ) $dsn['dbindex'] = 0;

        $id = md5(serialize($dsn));

        $dsn['id'] = $id;

        if ( empty( self::$instances[$id] ) )
        {
        	self::$instances[$id] = new RedisDatasource($dsn);
        }

        return self::$instances[$id];
	}

}

/**
 * Redis 数据源类
 */
class RedisDatasource
{

	/**
     * @var Redis
     */
    private $redis;

    function __construct(array $dsn)
    {
    	$this->dsn = $dsn;
        $this->connected = false;
    }

    function __destruct()
    {
    	$this->close();
    }

    function id()
	{
		return $this->dsn['id'];
	}

	function connect()
	{
		if ($this->connected) return;

		$this->redis = new Redis();

		if ( $this->dsn['persistent'] )
		{
			$func = 'pconnect';

			if ( is_array($this->dsn['dbpath']) )
			{
				$args = array(
						$this->dsn['dbpath']['host'],
						isset( $this->dsn['dbpath']['port'] ) ? $this->dsn['dbpath']['port'] : 6379,
						isset($this->dsn['timeout']) ? $this->dsn['timeout'] : null,
						isset($this->dsn['persistent_id']) ? $this->dsn['persistent_id'] : $this->dsn['id'],
						isset($this->dsn['retry_interval']) ? $this->dsn['retry_interval'] : null,
					);
			}
			else if ( is_string($this->dsn['dbpath']) && is_file($this->dsn['dbpath']) )
			{
				# unix domain socket.
				$args = array($this->dsn['dbpath']);
			}
			
		}
		else
		{
			$func = 'connect';

			if ( is_array($this->dsn['dbpath']) )
			{
				$args = array(
						$this->dsn['dbpath']['host'],
						isset( $this->dsn['dbpath']['port'] ) ? $this->dsn['dbpath']['port'] : 6379,
						isset($this->dsn['timeout']) ? $this->dsn['timeout'] : null,
						isset($this->dsn['reserved']) ? $this->dsn['reserved'] : null,
						isset($this->dsn['retry_interval']) ? $this->dsn['retry_interval'] : null,
					);
			}
			else if ( is_string($this->dsn['dbpath']) && is_file($this->dsn['dbpath']) )
			{
				# unix domain socket.
				$args = array($this->dsn['dbpath']);
			}
			
		}

		$ret = call_user_func_array(array($this->redis, $func), $args);

		if ( !$ret ){
			throw new RedisError("redis pconnect failed: {$this->dsn['id']}");
		}

		$this->redis->select( intval($this->dsn['dbindex']) );

		return $ret;
	}

    function close()
    {
        if ( !$this->dsn['persistent'] && !is_null($this->redis))
        {
            $this->redis = null;
            $this->connected = false;
        }
    }

    function redis()
    {
    	if (!$this->connected) $this->connect();
    	return $this->redis;
    }

}


class RedisError extends Exception {}
